#ifndef __MARS_GRAPHICS_MATERIAL_H__
#define __MARS_GRAPHICS_MATERIAL_H__

#include "MarsObject.h"
#include "MarsShader.h"
#include "MarsVertexShader.h"
#include "MarsPixelShader.h"
#include "MarsShaderParameter.h"
#include "MarsSharedPtr.h"

namespace Graphics
{

class Texture;
class SamplerState;
class BlendState;
class RasterizerState;

typedef struct _ShaderMaterial
{
	XMFLOAT4						Ambient;
	XMFLOAT4						Diffuse;
	XMFLOAT4						Specular; // w = SpecPower
	XMFLOAT4						Reflect;
} ShaderMaterial;

class Material : public Object, public RefCountObject
{
public:
									Material();
	virtual							~Material();

	void							SetVertexShader( VertexShader* pVertexShader );
	void							SetPixelShader( PixelShader* pPixelShader );
	void							SetDiffuseMap( Texture* pDiffuseMap, SamplerState* pDiffuseSS );

	void							SetBlendState( BlendState* pBlendState );
	void							SetRasterizerState( RasterizerState* pRasterizerState );
	
	void							SetAmbientColor( const XMFLOAT4& fAmbientColor );
	void							SetDiffuseColor( const XMFLOAT4& fDiffuseColor );
	void							SetSpecularColor( const XMFLOAT4& fSpecularColor );

	void							SetShininess( float fShininess );

	VertexShader*					GetVertexShader() const;
	PixelShader*					GetPixelShader() const;
	
	Texture*						GetDiffuseMap() const;
	SamplerState*					GetDiffuseSamplerState() const;

	BlendState*						GetBlendState() const;
	RasterizerState*				GetRasterizerState() const;

	const XMFLOAT4&					GetAmbientColor() const;
	const XMFLOAT4&					GetDiffuseColor() const;
	const XMFLOAT4&					GetSpecularColor() const;

	float							GetShininess() const;

	void							SetParameter( ShaderSemantic semantic, void* pBuffer );

	void							Bind();
	void							Unbind();

private:
	VertexShader*					m_pVertexShader;
	PixelShader*					m_pPixelShader;

	Texture*						m_pDiffuseMap;
	SamplerState*					m_pDiffuseSS;

	BlendState*						m_pBlendState;
	RasterizerState*				m_pRasterizerState;

	XMFLOAT4						m_fAmbientColor;
	XMFLOAT4						m_fDiffuseColor;
	XMFLOAT4						m_fSpecularColor;

	float							m_fShininess;
};

inline Material::~Material()
{

}

inline void Material::SetVertexShader( VertexShader* pVertexShader )
{
	m_pVertexShader = pVertexShader;
}

inline void Material::SetPixelShader( PixelShader* pPixelShader )
{
	m_pPixelShader = pPixelShader;
}

inline VertexShader* Material::GetVertexShader() const
{
	return m_pVertexShader;
}

inline PixelShader* Material::GetPixelShader() const
{
	return m_pPixelShader;
}

inline Texture* Material::GetDiffuseMap() const
{
	return m_pDiffuseMap;
}

inline SamplerState* Material::GetDiffuseSamplerState() const
{
	return m_pDiffuseSS;
}

inline BlendState* Material::GetBlendState() const
{
	return m_pBlendState;
}

inline RasterizerState* Material::GetRasterizerState() const
{
	return m_pRasterizerState;
}

inline void Material::SetAmbientColor( const XMFLOAT4& fAmbientColor )
{
	m_fAmbientColor = fAmbientColor;
}

inline void Material::SetDiffuseColor( const XMFLOAT4& fDiffuseColor )
{
	m_fDiffuseColor = fDiffuseColor;
}

inline void Material::SetSpecularColor( const XMFLOAT4& fSpecularColor )
{
	m_fSpecularColor = fSpecularColor;
}

inline void Material::SetShininess( float fShininess )
{
	m_fShininess = fShininess;
}

inline const XMFLOAT4& Material::GetAmbientColor() const
{
	return m_fAmbientColor;
}

inline const XMFLOAT4& Material::GetDiffuseColor() const
{
	return m_fDiffuseColor;
}

inline const XMFLOAT4& Material::GetSpecularColor() const
{
	return m_fSpecularColor;
}

inline float Material::GetShininess() const
{
	return m_fShininess;
}

inline void Material::Bind() 
{
	ShaderMaterial matParam;
	matParam.Ambient = m_fAmbientColor;
	matParam.Diffuse = m_fDiffuseColor;
	matParam.Specular = m_fSpecularColor;
	matParam.Specular.w = m_fShininess;
	SetParameter( SS_Material, &matParam );

	if ( m_pVertexShader )
		m_pVertexShader->UploadParameters();

	if ( m_pPixelShader )
		m_pPixelShader->UploadParameters();
}

inline void Material::Unbind()
{
	
}

inline void Material::SetParameter( ShaderSemantic semantic, void* pBuffer )
{
	if ( m_pVertexShader )
		m_pVertexShader->SetParameter( semantic, pBuffer );

	if ( m_pPixelShader )
		m_pPixelShader->SetParameter( semantic, pBuffer );
}

typedef SharedPtr< Material > MaterialPtr;

} // end of namespace Graphics

#endif // end of #ifndef __MARS_GRAPHICS_MATERIAL_H__